using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using System.Reflection;
using System.Globalization;

namespace XTengine.ComponentModel
{
    public static class TypeConverters
    {
        private static Dictionary<Type, Type> Converters = new Dictionary<Type, Type>();

        static TypeConverters()
        {
            Converters[typeof(string)] = typeof(StringConverter);
            Converters[typeof(float)] = typeof(SingleConverter);
            Converters[typeof(bool)] = typeof(BoolConverter);
            Converters[typeof(byte)] = typeof(ByteConverter);
            Converters[typeof(sbyte)] = typeof(SByteConverter);
            Converters[typeof(char)] = typeof(CharConverter);
            Converters[typeof(double)] = typeof(DoubleConverter);
            Converters[typeof(Int16)] = typeof(Int16Converter);
            Converters[typeof(Int32)] = typeof(Int32Converter);
            Converters[typeof(Int64)] = typeof(Int64Converter);
            Converters[typeof(UInt16)] = typeof(UInt16Converter);
            Converters[typeof(UInt32)] = typeof(UInt32Converter);
            Converters[typeof(UInt64)] = typeof(UInt64Converter);
            Converters[typeof(Quaternion)] = typeof(QuaternionConverter);
            Converters[typeof(Color)] = typeof(ColorConverter);
            Converters[typeof(DateTime)] = typeof(DateTimeConverter);
            Converters[typeof(TimeSpan)] = typeof(TimeSpanConverter);
            Converters[typeof(Vector2)] = typeof(Vector2Converter);
            Converters[typeof(Vector3)] = typeof(Vector3Converter);
            Converters[typeof(Vector4)] = typeof(Vector4Converter);
            Converters[typeof(BoundingBox)] = typeof(BoundingBoxConverter);
            Converters[typeof(BoundingSphere)] = typeof(BoundingSphereConverter);
        }

        public static Type GetConverterForType(Type inputType)
        {
            Type converterType;
            if (Converters.TryGetValue(inputType, out converterType))
                return converterType;

            return null;
        }

        public static object Convert(Type destinationType, string value)
        {
            if (destinationType.IsEnum)
                return Enum.Parse(destinationType, value, true);

            Type converterType = GetConverterForType(destinationType);

            if (converterType == null)
                return Activator.CreateInstance(destinationType);

            MethodInfo info = converterType.GetMethod("ConvertFrom", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);

            if (info == null)
                throw new EntryPointNotFoundException("Cannot find method Convert on type " + converterType.Name);

            object[] arguments = { value };

            object result = info.Invoke(Activator.CreateInstance(converterType), BindingFlags.Public | BindingFlags.Instance, null, arguments, System.Globalization.CultureInfo.CurrentCulture);
            
            return result;
        }
    }
}
